﻿namespace WingBeats.CSS.Grid

open WingBeats.CSS
open WingBeats.CSS.AST

type paneMarginsSpecification =
    | NormalMargins
    | NoMargins
    | NoLeftMargin
    | NoRightMargin
type paneSpaceSpecification =
    | NoSpace
    | SpaceBefore         of int
    | SpaceAfter          of int
    | SpaceBeforeAndAfter of int*int
    | Center

exception RemainderNotEven
exception DomainItemCreatorGotWrongDataType

type Grid (totalColumns, gridWidth : int, margin : int) =
    member this.Width  = px gridWidth
    member this.Margin = px margin

    member this.PaneWidth columns =
        match columns with
        | 0 -> 0
        | _ -> gridWidth / totalColumns * columns

    member this.PaneDeclarations (columns,
                                  margins : paneMarginsSpecification,
                                  spaces  : paneSpaceSpecification) =
        let paneDeclarations (data : obj) =
            match data with
            | :? (int * paneMarginsSpecification * paneSpaceSpecification) as tuple ->
                let columns, margins, spaces = tuple
                let addToMarginsWhenCentered () =
                    match (totalColumns - columns) % 2 with
                    | 0 -> this.PaneWidth (totalColumns - columns) / 2
                    | _ -> raise RemainderNotEven

                let leftMargin = 
                    (match margins with 
                     | NormalMargins | NoRightMargin -> margin
                     | NoLeftMargin  | NoMargins     -> 0)
                    +
                    (match spaces with
                     | NoSpace | SpaceAfter _ -> 0
                     | SpaceBeforeAndAfter (cols, _)
                     | SpaceBefore cols       -> this.PaneWidth cols
                     | Center                 -> addToMarginsWhenCentered ())

                let rightMargin =
                    (match margins with
                     | NormalMargins | NoLeftMargin  -> margin
                     | NoRightMargin | NoMargins     -> 0)
                    +
                    (match spaces with
                     | NoSpace | SpaceBefore _ -> 0
                     | SpaceBeforeAndAfter (_, cols)
                     | SpaceAfter cols         -> this.PaneWidth cols
                     | Center                  -> addToMarginsWhenCentered ())

                let totalColumns =
                    columns + (match spaces with
                               | NoSpace                            -> 0
                               | SpaceBefore cols | SpaceAfter cols -> cols
                               | SpaceBeforeAndAfter (left, right)  -> left + right
                               | Center                             -> totalColumns - columns)

                let totalWidth = (this.PaneWidth totalColumns) - leftMargin - rightMargin
                
                Collection
                    [   
                        Float.left
                        Margin.left  (px leftMargin )
                        Margin.right (px rightMargin)
                        width        (px totalWidth )
                    ]
            | _ -> raise DomainItemCreatorGotWrongDataType

        DomainItemCreator (
            "PaneDeclarations", 
            (columns, margins, spaces),
            paneDeclarations
            )    

    member this.PaneDeclarations columns =
        this.PaneDeclarations (columns, NormalMargins, NoSpace)

    member this.PaneDeclarations (columns, margins) =
        this.PaneDeclarations (columns, margins, NoSpace) 

    member this.PaneDeclarations (columns, spaces) =
        this.PaneDeclarations (columns, NormalMargins, spaces)

    member this.ContainerDeclarations = 
        let containerDeclarations (o : obj) =
            match o with
            | :? Grid as grid -> Collection [ width grid.Width ]
            | _ -> raise DomainItemCreatorGotWrongDataType
        DomainItemCreator (
            "ContainerDeclarations",
            this,
            containerDeclarations
            )